package cn.rdtimes.wolfdsp.core.job;

import cn.rdtimes.wolfdsp.core.counter.PrefCounter;
import cn.rdtimes.wolfdsp.core.data.JobGraphState;
import cn.rdtimes.wolfdsp.core.data.TaskState;
import cn.rdtimes.wolfdsp.core.invoker.http.ResponseMessage;
import cn.rdtimes.wolfdsp.core.service.Ordered;
import cn.rdtimes.wolfdsp.core.service.Service;

import java.util.Map;

/**
 * 任务流程服务, 这里调用可以是异步调度
 * 有几个队列:
 * 1. 定义流程队列(定义调度任务流程)
 * 2. 已调度队列(已开始调度的流程,轮询和一次等)
 * 3. 调度执行队列(正在执行的流程)
 * 4. 完成调度队列(包括正常,异常,停止)
 * <p>
 * 所有调度的方法首要条件要验证是否此服务器执行
 * 实例类型:
 * 1. 流程定义,任务定义--定义流程DAG和任务信息
 * 2. 调度实例--调度创建流程和任务实例,并按时循环执行流程实例
 * 3. 流程实例,实例任务--流程执行和任务执行,不循环执行
 *
 * @author BZ
 */

public interface JobGraphService extends Service {

    /**
     * 启动服务,发生异常不能继续
     *
     * @throws Exception 抛出异常
     */
    void start() throws Exception;

    /**
     * 支持重新启动，目的是为了状态由standby转换master
     *
     * @throws Exception 抛出异常
     */
    default void restart() throws Exception {
        shutdown();
        start();
    }

    /**
     * 停止任务
     */
    void shutdown();

    default String getName() {
        return "JobGraphService";
    }

    /**
     * @return 优先级要最低
     */
    default int order() {
        return Ordered.ORDER_NORMAL + 1000;
    }

    /**
     * @return 返回调度实例的各种类型计数器
     */
    PrefCounter[] getPrefCounter();

    /**
     * 指定jobId装载流程定义,并生成调度实例
     *
     * @param jobId 流程id
     * @throws Exception 这里未分解具体异常
     */
    void schedule(String jobId) throws Exception;

    /**
     * 重新装载调度实例继续执行,不创建新的调度任务。目的是解决故障或ha状态转移
     * 注意这个只有主服务器发生故障需要转移到备服务器时使用
     *
     * @param jobId 流程id
     * @throws Exception 这里未分解具体异常
     *                   如果存在调度实例抛出异常
     */
    void scheduleContinue(String jobId) throws Exception;

    /**
     * 继续在异常任务处执行流程,不影响调度实例
     *
     * @param instanceId 流程实例id
     * @param jobId      流程id
     * @return 流程实例状态
     * @throws Exception 这里未分解具体异常
     */
    JobGraphState jobInstanceContinue(String instanceId, String jobId) throws Exception;

    /**
     * 停止执行中的流程,不影响调度实例
     *
     * @param instanceId 流程实例id
     * @param jobId      流程id
     * @return 流程实例状态
     * @throws Exception 这里未分解具体异常
     */
    JobGraphState killJobInstance(String instanceId, String jobId) throws Exception;

    /**
     * 重新运行任务(不影响调度流程实例), 如果需要继续流程执行需要再次调用流程继续执行
     * 通常是执行失败或异常或跳过才可以重新运行(并且设置允许重新运行标志)
     *
     * @param instanceId 流程实例id
     * @param jobId      流程id
     * @param taskId     任务id
     * @return 任务实例状态
     * @throws Exception 这里未分解具体异常
     */
    TaskState againRunTask(String instanceId, String jobId, String taskId) throws Exception;

    /**
     * 任务节点汇报进度
     *
     * @param request 请求参数
     * @return 返回响应对象
     */
    ResponseMessage<?> taskReportRequest(Map<String, Object> request);

    /**
     * 调度状态变化,流程和任务完成时通知
     */
    interface CompletedListener {

        /**
         * 调度实例完成通知
         *
         * @param jobId 流程id
         * @param cause 异常时的异常信息
         */
        void onScheduledCompleted(String jobId, Throwable cause);

        /**
         * 调度流程实例完成时调用,可以通过状态开判断处理的逻辑
         *
         * @param jobId      流程id
         * @param instanceId 实例id
         * @param state      流程状态
         * @param cause      异常时的异常信息
         */
        void onJobGraphCompleted(String jobId, String instanceId, JobGraphState state, Throwable cause);

        /**
         * 每个任务完成时调用,可以通过状态判断处理的逻辑
         *
         * @param jobId      流程id
         * @param instanceId 实例id
         * @param taskId     任务id
         * @param state      任务状态
         * @param cause      异常时的异常信息
         */
        void onTaskCompleted(String jobId, String instanceId, String taskId, TaskState state, Throwable cause);
    }

    /**
     * 设置监听器
     *
     * @param listener 监听器
     */
    void setCompletedListener(CompletedListener listener);

    /**
     * @return 返回监听器
     */
    CompletedListener getCompletedListener();

}
